package com.sc.nft.helper;

import cn.hutool.core.date.SystemClock;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.mate.sdk.Keys;
import com.mate.sdk.blockchain.BlockChainClient;
import com.mate.sdk.domain.*;
import com.mate.sdk.domain.nft.NftInfo;
import com.sc.nft.callback.*;
import com.sc.nft.config.chain.BlockChainClientFactory;
import com.sc.nft.dao.UserChainInfoDao;
import com.sc.nft.dao.UserCollectionDao;
import com.sc.nft.entity.*;
import com.sc.nft.enums.ChainCallBackTypeEnum;
import com.sc.nft.enums.CollectionChainDealStatusEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;


@Component
@RequiredArgsConstructor
@Slf4j
public class MetaChainHepler {


//    private final BlockChainClient client;
    private final DeployNFTCallBack deployNFTCallBack;
    private final MintCallBack mintCallBack;
    private final MintBatchCallBack mintBatchCallBack;
    private final TransferCallBack transferCallBack;
    private final TransferToMetaWalletCallBack transferToMetaWalletCallBack;
    private final TransferFromMetaWalletCallBack transferFromMetaWalletCallBack;
    private final UpdateMetaDataCallBack updateMetaDataCallBack;
    private final UpdateMetaDataBatchCallBack updateMetaDataBatchCallBack;
    private final RecycleCollectionCallBack recycleCollectionCallBack;
    private final BurnNFTCallBack burnNFTCallBack;
    private final EcologyDestroyCollectionCallBack ecologyDestroyCollectionCallBack;
    private final TradingDestroyCollectionCallBack tradingDestroyCollectionCallBack;
    private final PledgeDestroyCollectionCallBack pledgeDestroyCollectionCallBack;
    private final UserChainInfoDao userChainInfoDao;
    private final UserCollectionDao userCollectionDao;


    /**
     * ⽤户链上身份⽣成
     *
     * @return
     */
    public Key userRegister() {
        return Keys.generateKey();
    }


    public static void main(String[] args) {
        System.out.println("0x521EF15AAa77056582B3802656bfC79217bdFbD1".toLowerCase(Locale.ROOT));

    }

    /**
     * 创建藏品合约
     *
     * @param collection    藏品
     * @return
     */
    public String deployNFT(DigitalCollection collection) {
        UserChainInfo userChainInfo = userChainInfoDao.getRegisterByUserId(1L);
        log.info("创建藏品合约 NFT名称:{},NFT数量:{}", collection.getFirstTitle(), collection.getSumCount());

        NftInfo nftInfo = new NftInfo(collection.getFirstTitle(), collection.getSumCount());

        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        ChainRequestLog chainRequestLog = new ChainRequestLog();
        chainRequestLog.setMethodName(ChainCallBackTypeEnum.DEPLOY.getDescription());
        chainRequestLog.setRequestUrl(client.getRpcAddr());
        chainRequestLog.setRequestParams(StrUtil.format("privateKey:{},NFT数据:{}", userChainInfo.getUserKey(), JSONUtil.toJsonStr(nftInfo)));
        chainRequestLog.setMethodType(ChainCallBackTypeEnum.DEPLOY);
        chainRequestLog.insert();

        TransactionResult result = client.deployNFT(userChainInfo.getUserKey(), nftInfo, deployNFTCallBack);
        // 3.发⾏商品结果（交易哈希）
        log.info(StrUtil.format("创建藏品合约结果: {}", result));
        // 6.校验发⾏商品结果
        Assert.isTrue(StrUtil.equals(result.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("发⾏商品失败,原因:{}", result.getMessage())));

        return result.getTransactionHash();
    }


    /**
     * 藏品铸造
     *
     * @param privateKey
     * @param contractAddress
     * @return
     */
    public String mint(String privateKey, String contractAddress, String id, String firstTitle, String price,String url) {

        log.info("藏品铸造 合约地址:{},id:{},价格:{},私钥:{}", contractAddress, id, price, privateKey);
        Map<String, String> metaData = new HashMap<String, String>() {{
            put("id", id);
            put("name", firstTitle);
//            put("price", price);
            put("url", url);
        }};
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        // 使⽤客户端，调⽤发⾏接⼝
        ChainRequestLog chainRequestLog = new ChainRequestLog();
        chainRequestLog.setMethodName(ChainCallBackTypeEnum.MINT.getDescription());
        chainRequestLog.setRequestUrl(client.getRpcAddr());
        chainRequestLog.setRequestParams(StrUtil.format("私钥:{},合约地址:{},元数据:{}",privateKey, contractAddress,JSONUtil.toJsonStr(metaData)));
        chainRequestLog.setMethodType(ChainCallBackTypeEnum.MINT);
        chainRequestLog.insert();


        TransactionResult transactionResult = client.mint(privateKey, contractAddress, metaData, mintCallBack);

        // 交易结果
        log.info(StrUtil.format("藏品铸造结果: {}", transactionResult));
        //校验结果
        Assert.isTrue(StrUtil.equals(transactionResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("发⾏商品失败,原因:{}", transactionResult.getMessage())));

        return transactionResult.getTransactionHash();
    }

    /**
     * 批量铸造
     *
     * @param privateKey
     * @param contractAddress
     * @param ids
     * @param firstTitle
     * @param price
     * @return
     */
    public String mintBatch(String privateKey, String contractAddress, List<String> ids, String firstTitle, String price,String url) {

        log.info("藏品批量铸造 合约地址:{},价格:{},私钥:{}", contractAddress, price, privateKey);
        log.info("藏品批量铸造 ids:{}", ids.toString());

        List<Map> nftMetaDatas = ids.stream().map(id -> {
            return new HashMap<String, String>() {{
                put("id", id);
                put("name", firstTitle);
//                put("price", price);
                put("url", url);
            }};
        }).collect(Collectors.toList());
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        log.info("藏品批量铸造 合约地址:{},私钥:{},元数据:{}", contractAddress, privateKey, nftMetaDatas);
        ChainRequestLog chainRequestLog = new ChainRequestLog();
        chainRequestLog.setMethodName(ChainCallBackTypeEnum.MINT_BATCH.getDescription());
        chainRequestLog.setRequestUrl(client.getRpcAddr());
        chainRequestLog.setRequestParams(StrUtil.format("privateKey:{},合约地址:{},元数据起始值:{},元数据末尾值:{}",privateKey, contractAddress,JSONUtil.toJsonStr(nftMetaDatas.get(0)),JSONUtil.toJsonStr(nftMetaDatas.get(nftMetaDatas.size()-1))));
        chainRequestLog.setMethodType(ChainCallBackTypeEnum.MINT_BATCH);
        chainRequestLog.insert();

        // 调⽤批量发⾏ NFT
        TransactionResult transactionResult = client.mintBatch(privateKey, contractAddress, nftMetaDatas, mintBatchCallBack);
        // 交易结果
        log.info(StrUtil.format("藏品批量铸造结果: {}", transactionResult));
        //校验结果
        Assert.isTrue(StrUtil.equals(transactionResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("发⾏商品失败,原因:{}", transactionResult.getMessage())));

        return transactionResult.getTransactionHash();

    }

    /**
     * 交易
     *
     * @param privateKey
     * @param contractAddress
     * @param tokenId
     * @param toAddress
     * @return
     */
    public String transfer(String privateKey, String contractAddress, Integer tokenId, String toAddress) {
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        ChainRequestLog chainRequestLog = new ChainRequestLog();
        chainRequestLog.setMethodName(ChainCallBackTypeEnum.TRANSFER.getDescription());
        chainRequestLog.setRequestUrl(client.getRpcAddr());
        chainRequestLog.setRequestParams(StrUtil.format("privateKey:{},contractAddress:{},tokenId:{},toAddress:{},", privateKey, contractAddress, tokenId, toAddress));
        chainRequestLog.setMethodType(ChainCallBackTypeEnum.TRANSFER);
        chainRequestLog.insert();

        TransactionResult transactionResult = client.transfer(privateKey, contractAddress, tokenId, toAddress, transferCallBack);
        //校验结果
        Assert.isTrue(StrUtil.equals(transactionResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("发⾏商品失败,原因:{}", transactionResult.getMessage())));
        return transactionResult.getTransactionHash();
    }

    public void transferLocal(String privateKey, String contractAddress, Integer tokenId, String toAddress) {
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();

        TransactionResult transactionResult = client.transfer(privateKey, contractAddress, tokenId, toAddress, transferCallBack);
        //校验结果
        Assert.isTrue(StrUtil.equals(transactionResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("发⾏商品失败,原因:{}", transactionResult.getMessage())));
        log.info("交易结果:{}",transactionResult.getTransactionHash());
    }

    /**
     * 转增到玛特钱包
     * @param privateKey
     * @param contractAddress
     * @param tokenId
     * @param toAddress
     * @return
     */
    public String transferToMetaWallet(String privateKey, String contractAddress, Integer tokenId, String toAddress) {

        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        ChainRequestLog chainRequestLog = new ChainRequestLog();
        chainRequestLog.setMethodName(ChainCallBackTypeEnum.TRANSFER_TO_META_WALLET.getDescription());
        chainRequestLog.setRequestUrl(client.getRpcAddr());
        chainRequestLog.setRequestParams(StrUtil.format("privateKey:{},contractAddress:{},tokenId:{},toAddress:{},", privateKey, contractAddress, tokenId, toAddress));
        chainRequestLog.setMethodType(ChainCallBackTypeEnum.TRANSFER_TO_META_WALLET);
        chainRequestLog.insert();

        TransactionResult transactionResult = client.transfer(privateKey, contractAddress, tokenId, toAddress, transferToMetaWalletCallBack);
        //校验结果
        Assert.isTrue(StrUtil.equals(transactionResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("跨链转增藏品失败,原因:{}", transactionResult.getMessage())));
        return transactionResult.getTransactionHash();
    }

    public String transferFromMetaWallet(String privateKey, String contractAddress, Integer tokenId, String toAddress) {
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        ChainRequestLog chainRequestLog = new ChainRequestLog();
        chainRequestLog.setMethodName(ChainCallBackTypeEnum.TRANSFER_FROM_META_WALLET.getDescription());
        chainRequestLog.setRequestUrl(client.getRpcAddr());
        chainRequestLog.setRequestParams(StrUtil.format("privateKey:{},contractAddress:{},tokenId:{},toAddress:{},", privateKey, contractAddress, tokenId, toAddress));
        chainRequestLog.setMethodType(ChainCallBackTypeEnum.TRANSFER_FROM_META_WALLET);
        chainRequestLog.insert();

        TransactionResult transactionResult = client.transfer(privateKey, contractAddress, tokenId, toAddress, transferFromMetaWalletCallBack);
        //校验结果
        Assert.isTrue(StrUtil.equals(transactionResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("发⾏商品失败,原因:{}", transactionResult.getMessage())));
        return transactionResult.getTransactionHash();
    }
    /**
     * 交易
     *
     * @param privateKey
     * @param contractAddress
     * @param tokenId
     * @param toAddress
     * @return
     */
    public String recycleCollection(String privateKey, String contractAddress, Integer tokenId, String toAddress) {
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        log.info("藏品交易 合约地址:{},编号:{},目标地址:{},私钥:{}", contractAddress, tokenId, toAddress, privateKey);
        ChainRequestLog chainRequestLog = new ChainRequestLog();
        chainRequestLog.setMethodName(ChainCallBackTypeEnum.RECYCLE.getDescription());
        chainRequestLog.setRequestUrl(client.getRpcAddr());
        chainRequestLog.setRequestParams(StrUtil.format("privateKey:{},contractAddress:{},tokenId:{},toAddress:{},", privateKey, contractAddress, tokenId, toAddress));
        chainRequestLog.setMethodType(ChainCallBackTypeEnum.RECYCLE);
        chainRequestLog.insert();

        TransactionResult transactionResult = client.transfer(privateKey, contractAddress, tokenId, toAddress, recycleCollectionCallBack);
        // 交易结果
        log.info(StrUtil.format("藏品交易结果: {}", transactionResult));
        //校验结果
        Assert.isTrue(StrUtil.equals(transactionResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("发⾏商品失败,原因:{}", transactionResult.getMessage())));
        return transactionResult.getTransactionHash();
    }




    /**
     * 数字商品元数据更新
     *
     * @param metaData
     * @return
     */
    public Map<String, String> updateMetaData(CollectionChainInitDetailsLog collectionChainInitDetailsLog, Map<String, String> metaData) {
        UserChainInfo userChainInfo = userChainInfoDao.getRegisterByUserId(1L);
        log.info("藏品元数据更新 合约地址:{},编号:{}", collectionChainInitDetailsLog.getContractAddress(), collectionChainInitDetailsLog.getTokenId());
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();

        String privateKey = userChainInfo.getUserKey();
        if(collectionChainInitDetailsLog.getDealStatus()== CollectionChainDealStatusEnum.TRADED){
            UserCollection collectionIdAndNumbering = userCollectionDao.getCollectionIdAndNumbering(collectionChainInitDetailsLog.getCollectionId(), collectionChainInitDetailsLog.getNumbering());
            privateKey = userChainInfoDao.getRegisterByUserId(collectionIdAndNumbering.getUserId()).getUserKey();
        }

        // 1.调⽤更新元数据接⼝
        TransactionResult transactionResult = client.updateMetaData(privateKey, collectionChainInitDetailsLog.getContractAddress(), collectionChainInitDetailsLog.getTokenId(), metaData, updateMetaDataCallBack);
        // 2.交易结果
        log.info("藏品元数据更新结果: {}", transactionResult);
        //校验结果
        Assert.isTrue(StrUtil.equals(transactionResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("数字商品元数据更新失败,原因:{}", transactionResult.getMessage())));

        return metaData;
    }

    /**
     * 数字商品元数据批量更新
     * @param contractAddress
     * @param tokenIds
     * @param metadatas
     * @return
     */
    public String updateMetaDataBatch(String contractAddress, List<Integer> tokenIds,List<Map> metadatas) {
        UserChainInfo userChainInfo = userChainInfoDao.getRegisterByUserId(1L);
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        ChainRequestLog chainRequestLog = new ChainRequestLog();
        chainRequestLog.setMethodName(ChainCallBackTypeEnum.UPDATE_META_DATA_BATCH.getDescription());
        chainRequestLog.setRequestUrl(client.getRpcAddr());
//        chainRequestLog.setRequestParams(StrUtil.format("contractAddress:{},tokenIds:{},metadatas:{}",contractAddress,tokenIds,metadatas.get(0)));
        chainRequestLog.setMethodType(ChainCallBackTypeEnum.UPDATE_META_DATA_BATCH);
        chainRequestLog.insert();

        // 1.调⽤更新元数据接⼝
        TransactionResult transactionResult = client.updateMetaDataBatch(userChainInfo.getUserKey(), contractAddress, tokenIds, metadatas, updateMetaDataBatchCallBack);
        // 2.交易结果
        log.info(StrUtil.format("藏品元数据更新结果: {}", transactionResult));
        //校验结果
        Assert.isTrue(StrUtil.equals(transactionResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("数字商品元数据更新失败,原因:{}", transactionResult.getMessage())));

        return transactionResult.getTransactionHash();
    }

    /**
     * 查询数字商品元数据
     *
     * @param contractAddress
     * @param tokenId
     * @return
     */
    public Map getMetaData(String contractAddress, Integer tokenId) {
        log.info("查询数字商品元数据 合约地址:{},编号:{}", contractAddress, tokenId);
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        MetaDataResult metaDataResult = client.getMetaData(contractAddress, tokenId);
        //校验结果
        Assert.isTrue(StrUtil.equals(metaDataResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("数字商品元数据查询失败,原因:{}", metaDataResult.getMessage())));
        log.info(StrUtil.format("查询数字商品元数据结果: {}", metaDataResult));

        return metaDataResult.getMetaData();
    }

    /**
     * 查询数字商品归属
     *
     * @param contractAddress
     * @param tokenId
     * @return owner 交易hash?
     */

    public String getNFTOwner(String contractAddress, Integer tokenId) {
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        OwnerResult ownerRes = client.getNFTOwner(contractAddress, tokenId);
        //校验结果
        Assert.isTrue(StrUtil.equals(ownerRes.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("查询数字商品归属失败,原因:{}", ownerRes.getMessage())));

        log.info(StrUtil.format("查询数字商品归属结果: {}", ownerRes));
        return ownerRes.getOwner();
    }

    public OwnerResult getNFTOwnerByResult(String contractAddress, Integer tokenId) {
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        return client.getNFTOwner(contractAddress, tokenId);
    }

    /**
     * 生态NFT销毁
     *
     * @param privateKey
     * @param contractAddress
     * @param tokenId
     * @return
     */
    public String ecologyDestroyCollection(String privateKey, String contractAddress, Integer tokenId) {
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        ChainRequestLog chainRequestLog = new ChainRequestLog();
        chainRequestLog.setMethodName(ChainCallBackTypeEnum.ECOLOGY_DESTROY.getDescription());
        chainRequestLog.setRequestUrl(client.getRpcAddr());
        chainRequestLog.setRequestParams(StrUtil.format("privateKey:{},contractAddress:{},tokenId:{}", privateKey, contractAddress, tokenId));
        chainRequestLog.setMethodType(ChainCallBackTypeEnum.ECOLOGY_DESTROY);
        chainRequestLog.insert();

        log.info(StrUtil.format("销毁NFT 合约地址:{},编号:{},私钥:{}", contractAddress, tokenId, privateKey));
        TransactionResult transactionResult = client.burnNFT(privateKey, contractAddress, tokenId, ecologyDestroyCollectionCallBack);
        log.info(StrUtil.format("销毁NFT结果: {}", transactionResult));
        //校验结果
        Assert.isTrue(StrUtil.equals(transactionResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("销毁NFT失败,原因:{}", transactionResult.getMessage())));
        return transactionResult.getTransactionHash();
    }
    /**
     * 交易池NFT销毁
     *
     * @param privateKey
     * @param contractAddress
     * @param tokenId
     * @return
     */
    public String tradingDestroyCollection(String privateKey, String contractAddress, Integer tokenId) {
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        ChainRequestLog chainRequestLog = new ChainRequestLog();
        chainRequestLog.setMethodName(ChainCallBackTypeEnum.TRADING_DESTROY.getDescription());
        chainRequestLog.setRequestUrl(client.getRpcAddr());
        chainRequestLog.setRequestParams(StrUtil.format("privateKey:{},contractAddress:{},tokenId:{}", privateKey, contractAddress, tokenId));
        chainRequestLog.setMethodType(ChainCallBackTypeEnum.TRADING_DESTROY);
        chainRequestLog.insert();

        log.info(StrUtil.format("交易池销毁NFT 合约地址:{},编号:{},私钥:{}", contractAddress, tokenId, privateKey));
        TransactionResult transactionResult = client.burnNFT(privateKey, contractAddress, tokenId, tradingDestroyCollectionCallBack);
        log.info(StrUtil.format("交易池销毁NFT结果: {}", transactionResult));
        //校验结果
        Assert.isTrue(StrUtil.equals(transactionResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("交易池销毁NFT失败,原因:{}", transactionResult.getMessage())));
        return transactionResult.getTransactionHash();
    }

    /**
     * 质押(燕琅嬛)NFT销毁
     *
     * @param privateKey
     * @param contractAddress
     * @param tokenId
     * @return
     */
    public String pledgeDestroyCollection(String privateKey, String contractAddress, Integer tokenId) {
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        ChainRequestLog chainRequestLog = new ChainRequestLog();
        chainRequestLog.setMethodName(ChainCallBackTypeEnum.PLEDGE_DESTROY.getDescription());
        chainRequestLog.setRequestUrl(client.getRpcAddr());
        chainRequestLog.setRequestParams(StrUtil.format("privateKey:{},contractAddress:{},tokenId:{}", privateKey, contractAddress, tokenId));
        chainRequestLog.setMethodType(ChainCallBackTypeEnum.PLEDGE_DESTROY);
        chainRequestLog.insert();

        log.info(StrUtil.format("质押销毁NFT 合约地址:{},编号:{},私钥:{}", contractAddress, tokenId, privateKey));
        TransactionResult transactionResult = client.burnNFT(privateKey, contractAddress, tokenId, pledgeDestroyCollectionCallBack);
        log.info(StrUtil.format("质押销毁NFT结果: {}", transactionResult));
        //校验结果
        Assert.isTrue(StrUtil.equals(transactionResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("质押销毁NFT失败,原因:{}", transactionResult.getMessage())));
        return transactionResult.getTransactionHash();
    }


    /**
     * 销毁 NFT
     *
     * @param privateKey
     * @param contractAddress
     * @param tokenId
     * @return
     */
    public String burnNFT(String privateKey, String contractAddress, Integer tokenId) {
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        ChainRequestLog chainRequestLog = new ChainRequestLog();
        chainRequestLog.setMethodName(ChainCallBackTypeEnum.BURN.getDescription());
        chainRequestLog.setRequestUrl(client.getRpcAddr());
        chainRequestLog.setRequestParams(StrUtil.format("privateKey:{},contractAddress:{},tokenId:{}", privateKey, contractAddress, tokenId));
        chainRequestLog.setMethodType(ChainCallBackTypeEnum.BURN);
        chainRequestLog.insert();

        log.info(StrUtil.format("销毁NFT 合约地址:{},编号:{},私钥:{}", contractAddress, tokenId, privateKey));
        TransactionResult transactionResult = client.burnNFT(privateKey, contractAddress, tokenId, burnNFTCallBack);
        log.info(StrUtil.format("销毁NFT结果: {}", transactionResult));
        //校验结果
        Assert.isTrue(StrUtil.equals(transactionResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("销毁NFT失败,原因:{}", transactionResult.getMessage())));
        return transactionResult.getTransactionHash();
    }

    /**
     * 获取地址余额
     * @param address
     * @return
     */
    public String getBalance(String address) {
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        return client.accountManager.getBalance(address).toString();
    }


    /**
     *  余额转账
     *  transferBalance
     * @param privateKey
     * @param toAddr
     * @param amount
     * @throws InterruptedException
     */

    public String transferBalance(String privateKey, String toAddr, BigInteger amount){
        BlockChainClient client = BlockChainClientFactory.getBeanInstance();
        TransactionResult transferResult = client.accountManager.transfer(privateKey, toAddr, amount);
        ChainRequestLog chainRequestLog = new ChainRequestLog();
        chainRequestLog.setMethodName(ChainCallBackTypeEnum.TRANSFER_BALANCE.getDescription());
        chainRequestLog.setRequestUrl(client.getRpcAddr());
        chainRequestLog.setRequestParams(StrUtil.format("privateKey:{},toAddr:{},amount:{}", privateKey, toAddr, amount));
        chainRequestLog.setMethodType(ChainCallBackTypeEnum.TRANSFER_BALANCE);
        chainRequestLog.insert();


        Assert.isTrue(StrUtil.equals(transferResult.getCode(), "OK"), () -> new GlobalRunTimeException(StrUtil.format("余额转账失败,原因:{}", transferResult.getMessage())));
        return transferResult.getTransactionHash();
    }


}
